import axios from 'axios'
import { ElMessage } from 'element-plus'

// Serialize params so that arrays become repeated keys:
// { a: ['x','y'] } -> a=x&a=y (compatible with Spring @RequestParam List<String>)
function serializeParams(params) {
  const usp = new URLSearchParams()
  const append = (key, val) => {
    if (val === undefined || val === null || val === '') return
    usp.append(key, String(val))
  }
  Object.entries(params || {}).forEach(([key, value]) => {
    if (Array.isArray(value)) {
      value.forEach(v => append(key, v))
    } else if (typeof value === 'object' && value !== null) {
      // flatten one level for plain objects
      Object.entries(value).forEach(([k, v]) => append(`${key}.${k}`, v))
    } else {
      append(key, value)
    }
  })
  return usp.toString()
}

const http = axios.create({
  baseURL: '/api',
  timeout: 15000,
  paramsSerializer: { serialize: serializeParams },
})

// 从 storage 读取 token（优先 localStorage，其次 sessionStorage）
function getToken() {
  return localStorage.getItem('token') || sessionStorage.getItem('token') || ''
}

function clearToken() {
  localStorage.removeItem('token')
  sessionStorage.removeItem('token')
}

function showError(message, cfg) {
  // 允许每个请求通过 config.showError === false 关闭全局提示
  if (cfg && cfg.showError === false) return
  if (!message) return
  ElMessage.error(message)
}

// 尝试从 JWT token 中解析 userId（兼容 base64url），失败则回退到本地缓存
function parseUserIdFromToken(token) {
  try {
    const parts = token.split('.')
    if (parts.length < 2) return null
    const base64url = parts[1]
    const base64 = base64url.replace(/-/g, '+').replace(/_/g, '/')
    const jsonStr = typeof atob === 'function' ? atob(base64) : Buffer.from(base64, 'base64').toString('binary')
    const payload = JSON.parse(decodeURIComponent(Array.prototype.map.call(jsonStr, c =>
      '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
    ).join('')))
    const id = payload.userId ?? payload.id ?? payload.uid ?? payload.sub
    return id != null ? String(id) : null
  } catch (e) {
    return null
  }
}

http.interceptors.request.use((config) => {
  const token = getToken()
  if (token) {
    config.headers = config.headers || {}
    config.headers.Authorization = `Bearer ${token}`
    // 附带 userId，便于后端从请求头读取当前用户（NoticeController.getCurrentUserId）
    const parsedId = parseUserIdFromToken(token)
    const storedId = localStorage.getItem('userId') || sessionStorage.getItem('userId')
    const userId = parsedId || storedId
    if (userId) {
      config.headers.userId = userId
    }
  }
  return config
})

http.interceptors.response.use(
    (res) => {
      // 统一处理业务错误：常见返回 { code, message, data } 或 { success, message, data }
      const payload = res?.data
      if (payload && (Object.prototype.hasOwnProperty.call(payload, 'code') || Object.prototype.hasOwnProperty.call(payload, 'success'))) {
        const code = payload.code
        const success = payload.success
        const ok = success === true || code === 0 || code === 200
        if (!ok) {
          const msg = payload.message || payload.msg || '请求失败，请稍后重试'
          showError(msg, res.config)
          return Promise.reject(new Error(msg))
        }
      }
      return res
    },
    (error) => {
      const status = error?.response?.status
      // 网络错误或超时/取消
      if (!error.response) {
        if (axios.isCancel?.(error)) {
          return Promise.reject(error)
        }
        if (error.code === 'ECONNABORTED' || /timeout/i.test(error.message || '')) {
          showError('请求超时，请检查网络后重试', error.config)
        } else {
          showError('网络异常，请检查网络连接', error.config)
        }
        return Promise.reject(error)
      }

      let msg = ''
      switch (status) {
        case 400: msg = '请求无效(400)'; break
        case 401:
          msg = '登录已过期，请重新登录'
          clearToken()
          if (typeof window !== 'undefined') {
            const current = window.location.pathname
            if (current !== '/login') {
              window.location.href = '/login'
            }
          }
          break
        case 403: msg = '没有权限(403)'; break
        case 404: msg = '接口不存在(404)'; break
        case 405: msg = '方法不被允许(405)'; break
        case 429: msg = '请求过于频繁(429)'; break
        case 500: msg = '服务器错误(500)'; break
        case 502: msg = '网关错误(502)'; break
        case 503: msg = '服务不可用(503)'; break
        case 504: msg = '网关超时(504)'; break
        default:
          msg = error?.response?.data?.message || error?.message || `请求错误(${status})`
      }
      showError(msg, error.config)
      return Promise.reject(error)
    }
)

// 文件下载方法
http.download = function(url, params, filename, config = {}) {
  return http({
    url,
    params,
    method: 'get',
    responseType: 'blob',
    ...config
  }).then(response => {
    // 从响应头获取文件名
    const contentDisposition = response.headers['content-disposition']
    let downloadFilename = filename
    
    if (contentDisposition) {
      const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)
      if (filenameMatch && filenameMatch[1]) {
        downloadFilename = filenameMatch[1].replace(/['"]/g, '')
      }
    }

    // 创建下载链接
    const blob = new Blob([response.data], { type: response.headers['content-type'] })
    const downloadUrl = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = downloadUrl
    link.download = downloadFilename
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(downloadUrl)
    
    return { code: 200, msg: '下载成功' }
  }).catch(error => {
    console.error('下载文件失败:', error)
    ElMessage.error('下载文件失败')
    throw error
  })
}

export default http
export { clearToken, getToken }
